/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.dusin.teachassist.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.ooxml.POIXMLDocument;
import org.apache.poi.ooxml.extractor.POIXMLTextExtractor;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.dusin.teachassist.matchalg.BasicData;
import org.dusin.teachassist.matchalg.MatchStrategy;
import org.dusin.teachassist.matchalg.MaxSubString;

/**
 *
 * @author dusin
 */
public class WordUtil {
    static String  splitPattern = "[\\t\\n\\r{}]";
    
    static MatchStrategy ms = new MaxSubString();
    //检查重复度
    public static Map<String,Object> checkSimilarity(InputStream fin,String srcfilename,String type, String dir) throws Exception {
        Map<String,Object> resultMap = new HashMap<String,Object>();
        double maxDegree = 0;
        String maxFilename = "";
        resultMap.put("degree", maxDegree);
        resultMap.put("filename", maxFilename);
        String srcText = getText(fin,type);
        String[] statements = srcText.split(splitPattern);
        List<String> statementSrcList = cleanData(statements);
        
        List<Path> paths = getAllValidFiles(dir);
        Map<String,List<String>> filesTexts = getAllTextList(paths);
        for(String filename:filesTexts.keySet()){
            if(srcfilename.equals(filename)){
                continue;
            }
            List<String> fileTextList = filesTexts.get(filename);
            double degree = getDegree(statementSrcList,fileTextList) ;
            if (degree > maxDegree){
                maxDegree = degree;
                maxFilename = filename;
            }
        }
        if(maxFilename!=null){
            System.out.println("max degree filename:"+maxFilename);
        }
        maxDegree = Math.round(maxDegree*1000)/1000.0;
        resultMap.put("degree", maxDegree);
        resultMap.put("filename", maxFilename);
        return resultMap;
    }

    private static String getText(Path pi) throws Exception {
        String msg = "文件格式错误";
        String text = null;
        OPCPackage opcPackage = null;
        POIXMLTextExtractor extractor = null;
        InputStream is = null;
        WordExtractor ex = null;
        String filename = pi.toFile().getName();
        try {
            //System.out.println("获取文字：" + filename);
            if (filename.endsWith("doc")) {
                is = new FileInputStream(pi.toFile());
                ex = new WordExtractor(is);
                text = ex.getText();

            } else if (filename.endsWith("docx")) {
                opcPackage = POIXMLDocument.openPackage(pi.toString());
                extractor = new XWPFWordExtractor(opcPackage);
                text = extractor.getText();
            } else {
                throw new Exception("文件后缀名错误");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("文件格式错误");
        } finally {
            boolean hasException = false;
            if (ex != null) {
                try {
                    ex.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    hasException = true;
                }
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException ex1) {
                    ex1.printStackTrace();
                    hasException = true;
                }
            }
            if (extractor != null) {
                try {
                    extractor.close();
                } catch (IOException ex1) {
                    ex1.printStackTrace();
                    hasException = true;

                }
            }
            if (hasException) {
                throw new Exception("文件格式错误");
            }
        }
        return text;
    }

    private static String getText(InputStream fis, String type) throws Exception {
        String msg = "文件格式错误";
        String text = null;
        XWPFWordExtractor extractor = null;

        WordExtractor ex = null;

        try {
            //System.out.println("获取文字：" + filename);
            if ("doc".equalsIgnoreCase(type)) {
                ex = new WordExtractor(fis);
                text = ex.getText();
            } else if ("docx".equalsIgnoreCase(type)) {
                XWPFDocument doc = new XWPFDocument(fis);
                extractor = new XWPFWordExtractor(doc);
                text = extractor.getText();
            } else {
                throw new Exception("文件后缀名错误");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("文件格式错误");
        } finally {
            boolean hasException = false;
            if (ex != null) {
                try {
                    ex.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    hasException = true;
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException ex1) {
                    ex1.printStackTrace();
                    hasException = true;
                }
            }
            if (extractor != null) {
                try {
                    extractor.close();
                } catch (IOException ex1) {
                    ex1.printStackTrace();
                    hasException = true;

                }
            }
            if (hasException) {
                throw new Exception("文件格式错误");
            }
        }
        return text;
    }
    
    //将目录下的所有doc，docx文档放入的map中，map的键为文件名，值为切割好的段落
    public static Map<String,List<String>> getAllTextList(List<Path> docFileList) {
        Map<String,List<String>> map = new HashMap<String,List<String>>();
        for (Path p : docFileList) {
            try {
                File file = p.toFile();
                String filename = file.getName();
                String text = getText(p);
                String[] statements = text.split(splitPattern);
                List<String> statementList = cleanData(statements);
                map.put(filename, statementList);
            } catch (Exception ex) {
                ex.printStackTrace();
                //continue;
            }
        }
        return map;
    }
    
    //过了掉一些不太好的数据，删除太短的句子
    private static List<String> cleanData(String[] a) {
        List<String> items = new ArrayList<String>();
        for (String sa : a) {
            if (sa.trim().length() < 5) {
                continue;
            }
            items.add(sa.trim());
        }
        return items;
    }
    
    //读取目录下所有word文档
    public static List<Path> getAllValidFiles(String directory) throws IOException {
        List<Path> filesList = new ArrayList<Path>();
        Path path = Paths.get(directory);
        DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path);
        for (Path p : directoryStream) {
            if (isValidFile(p)) {
                filesList.add(p);
            } 
        }
        return filesList;
    }
    
    public static boolean isValidFile(Path p) {
        String filename = p.toFile().getName();
        //String pattern = "^[\\d]{8,15}[\u4e00-\u9fa5]{1,6}(作业|实验|实验报告)\\d{1}.(docx|doc)$";
        String pattern = ".*.(docx|doc)$";
        return filename.matches(pattern);
    }
    
    // b和a的相似度  a为源文档，b为目标文档
    private static double getDegree(List<String> a, List<String> b) {
        double matchedLength = 0;
        int totalLength = 0;
        for (int i = 0; i < a.size(); i++) {
            totalLength += a.get(i).length();
            int beginIndex = i - 8 < 0 ? 0 : i - 8;
            int endIndex = i + 8 > b.size() ? b.size() : i + 8;
            int max = 0;
            for (int j = beginIndex; j < endIndex; j++) {
                int degree = ms.getMatchLength(a.get(i), b.get(j));
                if (max < degree) {
                    max = degree;
                }
                if ((double) max / a.get(i).length() > 0.99) {
                    break;
                }
            }
            matchedLength += max;
        }
        return (double) matchedLength / totalLength;
    }
}
